package game.entity.action;

import edu.monash.fit2099.engine.*;
import game.entity.actor.Allosaurs;
import game.entity.actor.Brachiosaur;
import game.entity.actor.Stegosaur;
import game.entity.behavior.PregnancyBehaviour;
import game.entity.behavior.WanderBehaviour;
import game.util.LocationUtil;

/**
 * Special Action for attacking other Actors.
 */
public class MoveToSexAction extends Action {

    /**
     * The Actor that is to be attacked
     */
    protected Actor target;

    /**
     * Constructor.
     *
     * @param target the Actor to attack
     */
    public MoveToSexAction(Actor target) {
        this.target = target;
    }

    @Override
    public String execute(Actor actor, GameMap map) {

        Location origin = map.locationOf(target);
        Location to = null;
        if (target instanceof Stegosaur) {
            to = findNearestStegosaur(origin, map);
        }
        if (target instanceof Brachiosaur) {
            to = findNearestBrachiosaurs(origin, map);
        }
        if (target instanceof Allosaurs) {
            to = findNearestAllosaurs(origin,map);
        }

        if (to != null) {
            Location nextStep = LocationUtil.calNextStep(origin, to);

            if (nextStep.canActorEnter(target)) {
                map.removeActor(target);
                nextStep.addActor(target);
            }

            String locationPrettyString = LocationUtil.getLocationPrettyString(origin);
            return locationPrettyString + target + " is moving to "
                    + LocationUtil.getLocationPrettyString(nextStep)
                    + " to sex, final dist is " + LocationUtil.getLocationPrettyString(to);
        }else{
            new WanderBehaviour().getAction(actor,map).execute(actor,map);
        }
        return actor+" no friend to sex, wandering...";
    }

    private  Location findNearestStegosaur(Location origin, GameMap map) {
        NumberRange widths = map.getXRange();
        NumberRange heights = map.getYRange();
        int minDistance = Integer.MAX_VALUE;
        String originSex = origin.getActor().getSex();
        Location to = null;
        for (int x : widths) {
            for (int y : heights) {
                Location here = map.at(x, y);
                Actor actor = here.getActor();
                int distance = LocationUtil.distance(origin, here);
                if (actor!=null &&
                        !(actor.getBehavior() instanceof PregnancyBehaviour)
                        && actor instanceof Stegosaur
                        && actor.isOppositeSex(originSex)
                        && distance < minDistance) {
                    minDistance = distance;
                    to = here;
                }
            }
        }
        return to;
    }

    private  Location findNearestBrachiosaurs(Location origin, GameMap map) {
        NumberRange widths = map.getXRange();
        NumberRange heights = map.getYRange();
        int minDistance = Integer.MAX_VALUE;
        String originSex = origin.getActor().getSex();
        Location to = null;
        for (int x : widths) {
            for (int y : heights) {
                Location here = map.at(x, y);
                Actor actor = here.getActor();
                int distance = LocationUtil.distance(origin, here);
                if (actor!=null &&
                        !(actor.getBehavior() instanceof PregnancyBehaviour)
                        && actor instanceof Brachiosaur
                        && actor.isOppositeSex(originSex)
                        && distance < minDistance) {
                    minDistance = distance;
                    to = here;
                }
            }
        }
        return to;
    }

    private  Location findNearestAllosaurs(Location origin, GameMap map) {
        NumberRange widths = map.getXRange();
        NumberRange heights = map.getYRange();
        int minDistance = Integer.MAX_VALUE;
        String originSex = origin.getActor().getSex();
        Location to = null;
        for (int x : widths) {
            for (int y : heights) {
                Location here = map.at(x, y);
                Actor actor = here.getActor();
                int distance = LocationUtil.distance(origin, here);
                if (actor!=null &&
                        !(actor.getBehavior() instanceof PregnancyBehaviour)
                        && actor instanceof Allosaurs
                        && actor.isOppositeSex(originSex)
                        && distance < minDistance) {
                    minDistance = distance;
                    to = here;
                }
            }
        }
        return to;
    }


    @Override
    public String menuDescription(Actor actor) {
        return actor + " attacks " + target;
    }


}
